package com.xxxx.car.appointment.service.impl;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxxx.car.appointment.domain.Statement;
import com.xxxx.car.appointment.enums.AppointmentStatusEnum;
import com.xxxx.car.appointment.vo.AppointmentVo;
import com.xxxx.car.appointment.vo.StatementVo;
import com.xxxx.car.common.core.redis.RedisCache;
import com.xxxx.car.common.utils.DateUtils;
import com.xxxx.car.common.utils.StringUtils;
import com.xxxx.car.system.service.impl.SysConfigServiceImpl;
import io.jsonwebtoken.lang.Assert;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.xxxx.car.appointment.mapper.AppointmentMapper;
import com.xxxx.car.appointment.domain.Appointment;
import com.xxxx.car.appointment.service.IAppointmentService;

import javax.annotation.Resource;

/**
 * 【请填写功能名称】Service业务层处理
 * 
 * @author Huang
 * @date 2024-08-23
 */
@Service
public class AppointmentServiceImpl extends ServiceImpl<AppointmentMapper,Appointment> implements IAppointmentService
{
    @Resource
    private AppointmentMapper appointmentMapper;
    @Autowired
    private SysConfigServiceImpl sysConfigService;
    @Autowired
    private RedisCache redisCache;
    @Resource
    private StatementServiceImpl statementService;

    /**
     * 查询【请填写功能名称】
     * 
     * @param id 【请填写功能名称】主键
     * @return 【请填写功能名称】
     */
    @Override
    public Appointment selectAppointmentById(Long id)
    {
        return appointmentMapper.selectAppointmentById(id);
    }

    /**
     * 查询【请填写功能名称】列表
     * 
     * @param appointment 【请填写功能名称】
     * @return 【请填写功能名称】
     */
    @Override
    public List<Appointment> selectAppointmentList(Appointment appointment)
    {
        return appointmentMapper.selectAppointmentList(appointment);
    }

    /**
     * 新增【请填写功能名称】
     * 
     * @param appointment 【请填写功能名称】
     * @return 结果
     */
    @Override
    public int insertAppointment(Appointment appointment)
    {
        appointment.setCreateTime(DateUtils.getNowDate());
        // 同一个手机号,一天只能预约5次
        //利用系统参数表,配置当天最大的预约次数参数,实现参数灵活配置
        String maxNumVal = sysConfigService.selectConfigByKey("car.appointment.max.num");
        if(StringUtils.isEmpty(maxNumVal)){
            maxNumVal = "5"; //如果未配置参数,则默认设置参数为5
        }
        Integer maxNum = Integer.valueOf(maxNumVal);
        // 利用redis 的有效时间 + 计数器可以实现当天次数累计操作
        LocalDateTime nowData = LocalDateTime.now();
        LocalDateTime targetData = LocalDateTime.of(nowData.getYear(), nowData.getMonth(), nowData.getDayOfMonth(), 23, 59, 59);
        Long seconds = DateUtils.getNowToTargetTimeSeconds(nowData, targetData, TimeUnit.SECONDS);
        if(seconds == null){
            seconds = TimeUnit.HOURS.toSeconds(24 - nowData.getHour());
        }
        String key = "car_appointment_num:" + appointment.getCustomerPhone();
        Long increment = redisCache.increment(key, 1, seconds, TimeUnit.SECONDS);
        Assert.state(maxNum > increment,"当天预约次数已经达到上限!");
        return appointmentMapper.insertAppointment(appointment);
    }

    /**
     * 修改【请填写功能名称】
     * 
     * @param appointmentVo 【请填写功能名称】
     * @return 结果
     */
    @Override
    public int updateAppointment(AppointmentVo appointmentVo)
    {
        Appointment appointment = appointmentMapper.selectAppointmentById(appointmentVo.getId());
        Assert.notNull(appointment,"参数错误!");
        Assert.state(AppointmentStatusEnum.APPOINTING.ordinal() == appointment.getStatus(),"只有预约中才允许修改");
        Appointment appointmentThis = new Appointment();
        BeanUtils.copyProperties(appointmentVo,appointmentThis);
        return appointmentMapper.updateAppointment(appointmentThis);
    }

    /**
     * 批量删除【请填写功能名称】
     * 
     * @param ids 需要删除的【请填写功能名称】主键
     * @return 结果
     */
    @Override
    public int deleteAppointmentByIds(Long[] ids)
    {
        return appointmentMapper.deleteAppointmentByIds(ids);
    }

    /**
     * 删除【请填写功能名称】信息
     * 
     * @param id 【请填写功能名称】主键
     * @return 结果
     */
    @Override
    public int deleteAppointmentById(Long id)
    {
        return appointmentMapper.deleteAppointmentById(id);
    }

    @Override
    public int updateArrival(Long id) {
        Appointment appointment = appointmentMapper.selectAppointmentById(id);
        Assert.notNull(appointment,"参数传递有误!");
        Assert.state(appointment.getStatus() == AppointmentStatusEnum.APPOINTING.ordinal(),"只有预约中的客户才能已到店");
        return appointmentMapper.updateArrival(id);
    }

    @Override
    public int cancelAppointment(Long id) {
        Appointment appointment = appointmentMapper.selectAppointmentById(id);
        Assert.notNull(appointment,"参数传递有误!");
        Assert.state(appointment.getStatus() == AppointmentStatusEnum.APPOINTING.ordinal(),"只有在预约中才能取消预约");
        return appointmentMapper.updateStatus(id,AppointmentStatusEnum.CANCEL.ordinal());
    }

    @Override
    public Statement doCreateStatement(Long id) {
        // 1.根据 id 查询预约信息
        Appointment appointment = appointmentMapper.selectAppointmentById(id);
        // 2.判断状态是否可以生成结算单
        List<Integer> status = Arrays.asList(AppointmentStatusEnum.ARRIVAL.ordinal(), AppointmentStatusEnum.PAID.ordinal(), AppointmentStatusEnum.STATEMENT.ordinal());
        Assert.state(status.contains(appointment.getStatus().intValue()),"该状态无法结算");
        // 3.根据预约 id 查询结算单信息,如果为空,生成结算单
        Statement statement = statementService.selectStatementByAppointmentId(id);
        if(statement == null){
            // 3.1 根据预约信息创建结算单
            statement = this.buildStatementVo(appointment);
            // 3.2 保存结算单
            statementService.insertStatementNormal(statement);
            // 3.3 更新预约状态为结算单生成
            appointmentMapper.updateStatus(id,AppointmentStatusEnum.STATEMENT.ordinal());
        }
        return statement;
    }

    private Statement buildStatementVo(Appointment appointment) {
        Statement statement = new Statement();
        statement.setTotalQuantity(BigDecimal.ZERO);
        statement.setTotalAmount(BigDecimal.ZERO);
        statement.setDiscountAmount(BigDecimal.ZERO);
        statement.setAppointmentId(appointment.getId());
        statement.setIsDelete(0L);
        statement.setStatus(Statement.CONSUMER);
        statement.setActualArrivalTime(appointment.getArrivalTime());
        statement.setCarType(appointment.getCarType());
        statement.setCustomerName(appointment.getCustomerName());
        statement.setCustomerPhone(appointment.getCustomerPhone());
        statement.setInfo(appointment.getRemark());
        statement.setCarNumber(appointment.getCarNumber());
        statement.setServiceType(appointment.getServiceType());
        return statement;
    }

    public int updatePaySuccess(Long appointmentId) {
        return appointmentMapper.updateStatus(appointmentId,AppointmentStatusEnum.PAID.ordinal());
    }
}
